/*************************MemoryRewriteChecker.cpp**************************
 * @file MemoryRewriteChecker.cpp                                          *
 * @author Comphsics                                                       *
 * @date 2021.2.2                                                          *
 * @details                                                                *
 *     This file implements memory rewrite checker                         *
 *                                                                         *
 ***************************************************************************/
#include "checkers/MemoryRewriteChecker.h"
#include <sstream>
extern ReportSpace::Report external_bug_report;


void MRDetail::SymbolPool::insert(Symbol::SymbolType*ST,size_t Id,const clang::Expr* E,bool Read){
    if(!ST){
        return;
    }
    const auto FindResult=Pool.find(ST);
    if(FindResult==Pool.end()){
        SymbolExprType List;
        Operation Tmp;
        Tmp.Id=Id;
        Tmp.Op=E;
        Tmp.Read=Read;
        List.emplace_back(std::move(Tmp));
        Pool.insert({ST,std::move(List)});
    }else {
        SymbolExprType &List = FindResult->getSecond();
        Operation Tmp;
        Tmp.Id = Id;
        Tmp.Op = E;
        Tmp.Read = Read;
        List.emplace_back(std::move(Tmp));
    }
}

void MRDetail::SymbolPool::insert(Symbol::SymbolType*ST,size_t Id,const std::vector<const clang::Expr*>& Es,bool Read){
    if(!ST){
        return;
    }
    const auto FindResult=Pool.find(ST);
    if(FindResult==Pool.end()){
        SymbolExprType List;
        for(const auto &Ele:Es){
            Operation Tmp;
            Tmp.Id=Id;
            Tmp.Op=Ele;
            Tmp.Read=Read;
            List.emplace_back(std::move(Tmp));
        }
        Pool.insert({ST,std::move(List)});
    }else {
        SymbolExprType &List = FindResult->getSecond();
        for(const auto &Ele:Es){
            Operation Tmp;
            Tmp.Id=Id;
            Tmp.Op=Ele;
            Tmp.Read=Read;
            List.emplace_back(std::move(Tmp));
        }
    }
}

void MRDetail::SymbolPool::replace(Symbol::SymbolType *ST,size_t LeftId,size_t RightId){
    if(LeftId==RightId){
        return;
    }
    if(!ST){
        return;
    }

    const auto FindResult=Pool.find(ST);
    if(FindResult==Pool.end()){
        return;
    }
    SymbolExprType& List=FindResult->getSecond();
    for(auto & Begin : List){
        if(Begin.Id==RightId){
            Begin.Id=LeftId;
        }
    }
}
void MRDetail::SymbolPool::replace(Symbol::SymbolType *ST,size_t LeftId,size_t RightId,bool Read){
    if(LeftId==RightId){
        return;
    }
    if(!ST){
        return;
    }

    const auto FindResult=Pool.find(ST);
    if(FindResult==Pool.end()){
        return;
    }
    SymbolExprType& List=FindResult->getSecond();
    for(auto & Begin : List){
        if(Begin.Id==RightId&&Begin.Read==Read){
            Begin.Id=LeftId;
        }
    }
}

void MRDetail::SymbolPool::update(Symbol::SymbolType*ST,size_t Id,const clang::Expr*E,bool Read){
    remove(ST,Id,Read);
    insert(ST,Id,E,Read);
}

void MRDetail::SymbolPool::update(Symbol::SymbolType*ST,size_t Id,const std::vector<const clang::Expr*>& Es,bool Read){
    remove(ST,Id,Read);
    insert(ST,Id,Es,Read);
}

void MRDetail::SymbolPool::remove(Symbol::SymbolType *ST,size_t Id){
    if(!ST){
        return;
    }
    const auto FindResult=Pool.find(ST);
    if(FindResult==Pool.end()){
        return;
    }
    SymbolExprType& List=FindResult->getSecond();
    for(auto Begin=List.begin();Begin!=List.end();){
        if(Begin->Id==Id){
            Begin=List.erase(Begin);
        }else{
			++Begin;
		}
    }
}

void MRDetail::SymbolPool::remove(Symbol::SymbolType *ST,size_t Id,bool Read){
    if(!ST){
        return;
    }
    const auto FindResult=Pool.find(ST);
    if(FindResult==Pool.end()){
        return;
    }
    SymbolExprType& List=FindResult->getSecond();
    for(auto Begin=List.begin();Begin!=List.end();){
        if(Begin->Id==Id&&Begin->Read==Read){
            Begin=List.erase(Begin);
        }else{
            ++Begin;
        }
    }
}

std::vector<const clang::Expr*> MRDetail::SymbolPool::getExprs(Symbol::SymbolType *ST,size_t Id){
    std::vector<const clang::Expr*> Ret;
    if(!ST){
        return Ret;
    }
    const auto FindResult=Pool.find(ST);

    if(FindResult==Pool.end()){
        return Ret;
    }
    SymbolExprType& List=FindResult->getSecond();
    for(auto Begin=List.begin();Begin!=List.end();++Begin){
        if(Begin->Id==Id){
			Ret.push_back(Begin->Op);
		}
    }
	return Ret;
}

std::vector<const clang::Expr*> MRDetail::SymbolPool::getExprs(Symbol::SymbolType *ST,size_t Id,bool Read){
    std::vector<const clang::Expr*> Ret;
    if(!ST){
        return Ret;
    }
    const auto FindResult=Pool.find(ST);

    if(FindResult==Pool.end()){
        return Ret;
    }
    SymbolExprType& List=FindResult->getSecond();
    for(auto Begin=List.begin();Begin!=List.end();++Begin){
        if(Begin->Id==Id&&Begin->Read==Read){
			Ret.push_back(Begin->Op);
		}
    }
	return Ret;
}

void MRDetail::SymbolPool::merge(Symbol::SymbolType *ST,size_t LeftId,size_t RightId){
    if(LeftId==RightId){
        return;
    }
    if(!ST){
        return;
    }
    const auto FindResult=Pool.find(ST);
    if(FindResult==Pool.end()){
        return;
    }
    SymbolExprType& List=FindResult->getSecond();
    for(auto & Begin : List){
        if(Begin.Id==RightId){
            insert(ST,LeftId,Begin.Op,Begin.Read);
        }
    }
}
void MRDetail::SymbolPool::merge(Symbol::SymbolType *ST,size_t LeftId,size_t RightId,bool Read){
    if(LeftId==RightId){
        return;
    }
    if(!ST){
        return;
    }
    const auto FindResult=Pool.find(ST);
    if(FindResult==Pool.end()){
        return;
    }
    SymbolExprType& List=FindResult->getSecond();
    for(auto & Begin : List){
        if(Begin.Id==RightId&&Begin.Read==Read){
            insert(ST,RightId,Begin.Op,Begin.Read);
        }
    }
}



void MRDetail::Flow::updateWith(Flow *Other){
    if(!Other){
        return;
    }
    for(const auto It:Other->Content){
        auto Result=Content.find(It.getFirst());
        if(Result!=Content.end()){
            unsigned char Value=static_cast<unsigned char>(It.getSecond().LastStatus);
            Result->getSecond().LastStatus=static_cast<MRDetail::StatusType>(Value);
        }else{
            MRDetail::SymbolStatus Status;
            Status.FirstStatus=It.getSecond().FirstStatus;
            Status.LastStatus=It.getSecond().LastStatus;
            Content.insert({It.getFirst(),Status});
        }
    }
}

void MRDetail::Flow::mergeWith(Flow *Else){
    if(!Else){
        for(auto& It:Content){
            unsigned char Value=static_cast<unsigned char>(It.getSecond().FirstStatus);
            Value|=0x004;// 0b100
            It.getSecond().FirstStatus=static_cast<MRDetail::StatusType>(Value);
            Value=static_cast<unsigned char>(It.getSecond().LastStatus);
            Value|=0x004;
            It.getSecond().LastStatus=static_cast<MRDetail::StatusType>(Value);
        }
        return;
    }
    for(const auto &It:Else->Content){
        auto Result=Content.find(It.getFirst());
        if(Result!=Content.end()){
            // both merge the first and last status.
            unsigned char Value=static_cast<unsigned char>(Result->getSecond().FirstStatus);
            Value|=static_cast<unsigned char>(It.getSecond().FirstStatus);
            Result->getSecond().FirstStatus=static_cast<MRDetail::StatusType>(Value);
            Value=static_cast<unsigned char>(Result->getSecond().LastStatus);
            Value|=static_cast<unsigned char>(It.getSecond().LastStatus);
            Result->getSecond().LastStatus=static_cast<MRDetail::StatusType>(Value);
        }else{
            MRDetail::SymbolStatus Status;
            unsigned char Value=static_cast<unsigned char>(It.getSecond().FirstStatus);
            Value|=0x004;// 0b100
            Status.FirstStatus=static_cast<MRDetail::StatusType>(Value);
            Value=static_cast<unsigned char>(It.getSecond().LastStatus);
            Value|=0x004;
            Status.LastStatus=static_cast<MRDetail::StatusType>(Value);
            Content.insert({It.getFirst(),Status});
        }
    }
    /// Else hadn't but this had.
    const auto ElseContent=Else->Content;
    for(auto& It:Content){
        auto Result=ElseContent.find(It.getFirst());
        if(Result==ElseContent.end()){
            unsigned char Value=static_cast<unsigned char>(It.getSecond().FirstStatus);
            Value|=0x004;// 0b100
            It.getSecond().FirstStatus=static_cast<MRDetail::StatusType>(Value);
            Value=static_cast<unsigned char>(It.getSecond().LastStatus);
            Value|=0x004;
            It.getSecond().LastStatus=static_cast<MRDetail::StatusType>(Value);
        }
    }
}

void MemoryRewriteAnalyzer::enterFunctionScope(const FunctionDecl*FD) {
    // FD has a body.
    CurrentFunction=FD;
    MainFlow=new MRDetail::Flow();
	assert(ThenFlows.empty());
	assert(PreFlows.empty());
}

void MemoryRewriteAnalyzer::enterIfScope(const clang::IfStmt *IS){
    FlowStack.push({IS,AnalyzedLevel,false});
    PreFlows.push(MainFlow);
    MainFlow=new MRDetail::Flow();
}

void MemoryRewriteAnalyzer::enterElseScope(const clang::IfStmt *IS) {
    FlowStack.push({IS,AnalyzedLevel,true});
    ThenFlows.push(MainFlow);
    MainFlow=new MRDetail::Flow();
}

void MemoryRewriteAnalyzer::enterSwitchScope(const clang::SwitchStmt*SS){
	FlowStack.push({SS,AnalyzedLevel,true});// just a flag.
}

// we need to handle this situation:
// case 'a':case 'b'...-----> The second case is the child of the first case
// but not the child of the top switch.
void MemoryRewriteAnalyzer::enterCaseScope(const clang::CaseStmt *CS){
	auto Top=std::get<2>(FlowStack.top());
	const clang::Stmt *S=std::get<0>(FlowStack.top());
	if(llvm::isa<clang::SwitchCase>(S)){
		// nested case or default.
		ThenFlows.push(MainFlow);
	}else if(Top){
		PreFlows.push(MainFlow);
		std::get<2>(FlowStack.top())=false;
	}else{
		ThenFlows.push(MainFlow);
	}
	FlowStack.push({CS,AnalyzedLevel,true});
	MainFlow=new MRDetail::Flow();
}

void MemoryRewriteAnalyzer::enterDefaultScope(const clang::DefaultStmt *DS){
	auto Top=std::get<2>(FlowStack.top());
	const clang::Stmt *S=std::get<0>(FlowStack.top());
	if(llvm::isa<clang::SwitchCase>(S)){
		// nested case or default.
		ThenFlows.push(MainFlow);
	}else if(Top){
		PreFlows.push(MainFlow);
		std::get<2>(FlowStack.top())=false;
	}else{
		ThenFlows.push(MainFlow);
	}
	FlowStack.push({DS,AnalyzedLevel,true});
	MainFlow=new MRDetail::Flow();
}

void MemoryRewriteAnalyzer::finishScope(Footprints *FP){
    if(AnalyzedLevel==0){
        return;
    }
    //clear the local symbols.
    for(auto It=MainFlow->Content.begin();It!=MainFlow->Content.end();It++){
        const auto ST=It->getFirst();
        if(FP->has(ST)) {
            MainFlow->Content.erase(It);
            Pool->Pool.erase(ST);
        }
    }
    // NOTICE: update the flow symbols here.
    // When exiting the flow scope.
    if(!FlowStack.empty()){
        const auto Top=FlowStack.top();
        const clang::Stmt *S=std::get<0>(Top);
        bool hasElse=std::get<2>(Top);
        if(std::get<1>(Top)==AnalyzedLevel){
            if(llvm::isa<clang::IfStmt>(S)){
                const auto *IS=llvm::cast<clang::IfStmt>(S);
                // exiting the else or this IfStmt has no else statement.
                if(hasElse){
                    auto Then=ThenFlows.top();
					mergeFlow(Then,MainFlow);
                    delete MainFlow;
					MainFlow=Then;
                    ThenFlows.pop();
                }else if(!IS->getElse()){
                    mergeFlow(MainFlow,nullptr);
                }else{
                    FlowStack.pop();
                    return;
                }
                // update MainFlow with PreFlow.
                auto Pre=PreFlows.top();
                checkAndUpdateFlow(Pre,MainFlow,false);
                delete MainFlow;
				MainFlow=Pre;
                PreFlows.pop();
            }else if(llvm::isa<clang::SwitchStmt>(S)){
				bool hasDefault=false;
				const auto *SS=llvm::cast<clang::SwitchStmt>(S);
				auto Child=SS->getSwitchCaseList();
				if(!Child){
					FlowStack.pop();
					return;
				}
				if(llvm::isa<clang::DefaultStmt>(*Child)){
					hasDefault=true;
				}
				do{
					Child=Child->getNextSwitchCase();
					if(Child){
						if(llvm::isa<clang::CaseStmt>(*Child)){
							auto Then=ThenFlows.top();
							mergeFlow(Then,MainFlow);
							delete MainFlow;
							MainFlow=Then;
							ThenFlows.pop();
						}else if(llvm::isa<clang::DefaultStmt>(*Child)){
							auto Then=ThenFlows.top();
							hasDefault=true;
							mergeFlow(Then,MainFlow);
							delete MainFlow;
							MainFlow=Then;
							ThenFlows.pop();
						}
					}else{
						break;
					}
				}while(1);
				if(!hasDefault){
					mergeFlow(MainFlow,nullptr);
				}
				// update MainFlow with PreFlow.
				auto Pre=PreFlows.top();
				checkAndUpdateFlow(Pre,MainFlow,false);
				delete MainFlow;
                MainFlow=Pre;
				PreFlows.pop();
			}
            FlowStack.pop();
        }
    }

    // when finish a function scope.
    if(AnalyzedLevel==1){		
        assert(MainFlow);
        auto Pair=std::make_pair(CurrentFunction, MainFlow);
        FunctionFlows.insert(Pair);
        CurrentFunction=nullptr;
    }
}


void MemoryRewriteAnalyzer::mergeFlow(MRDetail::Flow* Then,MRDetail::Flow* Else){
	if(!Else){
		Then->mergeWith(Else);
		return;
	}
	Then->mergeWith(Else);
	size_t LeftId0=computeEncryptedValue(Then,false);
	size_t RightId0=computeEncryptedValue(Else,false);
	size_t LeftId1=computeEncryptedValue(Then,true);
	size_t RightId1=computeEncryptedValue(Else,true);
	for(const auto& ElseEle:Else->Content){
		Pool->replace(ElseEle.getFirst(),LeftId0,RightId0);
		Pool->replace(ElseEle.getFirst(),LeftId1,RightId1);
	}
}



void MemoryRewriteAnalyzer::checkAndUpdateFlow(MRDetail::Flow* Before,MRDetail::Flow* After,bool Hold){
    size_t PreId=computeEncryptedValue(Before,false);
	size_t MainId=computeEncryptedValue(After,true);
    // check!
    for(const auto It:After->Content){
        auto Result=Before->Content.find(It.getFirst());
        const auto ST=It.getFirst();
		if(Result!=Before->Content.end()){    
            if(It.getSecond().FirstStatus==MRDetail::StatusType::WRITE
                &&(Result->getSecond().LastStatus==MRDetail::StatusType::PARTIALLYWRITE
                ||Result->getSecond().LastStatus==MRDetail::StatusType::WRITE
                ||Result->getSecond().LastStatus==MRDetail::StatusType::READWRITE
                ||Result->getSecond().LastStatus==MRDetail::StatusType::PARTIALLYREADWRITE))
            if(!DisableSimpleVariable||!(ST->is<Symbol::Normal*>()||ST->is<Symbol::Pointer*>())){
                if(occursNotInUncertainOrPointeeSymbol(ST)){
                    // report a warning
                    PatchInfo *Patch=convertToPatch(ST,MainId,PreId);
                    Patch->Variable=findDeclaration(ST);
                    Patches.push_back(Patch);
                    external_bug_report.addToReport(convertToReport(Patch));
                }
            }
            
        }
		if(Hold){
			Pool->remove(ST,PreId);
            Pool->merge(ST,PreId,computeEncryptedValue(After,false));
		}else{
			Pool->remove(ST,PreId);
            Pool->remove(ST,MainId);
            Pool->replace(ST,PreId,computeEncryptedValue(After,false));
		}
    }
    Before->updateWith(After);
}

void MemoryRewriteAnalyzer::checkAndUpdateSymbol(MRDetail::Flow* Current
        ,Symbol::SymbolType*ST,const clang::Expr *E,bool Read){
    if(!ST){
        return;
    }
	size_t InsertOpaque=computeEncryptedValue(Current,false);
    const auto CurrentResult=Current->Content.find(ST);
    // XXX: refactor?
    if(CurrentResult==Current->Content.end()){
        MRDetail::SymbolStatus Status;
        Status.FirstStatus=Read?
            MRDetail::StatusType::READ:MRDetail::StatusType::WRITE;
        Status.LastStatus=Status.FirstStatus;
        Current->Content.insert({ST,Status});
		// also insert to pool
		Pool->insert(ST,InsertOpaque,E,Read);
        InsertOpaque=computeEncryptedValue(Current,true);
        Pool->insert(ST,InsertOpaque,E,Read);
    }else{
        // !check!
        if(!Read&&(CurrentResult->getSecond().LastStatus==MRDetail::StatusType::WRITE
            ||CurrentResult->getSecond().LastStatus==MRDetail::StatusType::PARTIALLYWRITE)){
            if(!DisableSimpleVariable||!(ST->is<Symbol::Normal*>()||ST->is<Symbol::Pointer*>())){
                if(occursNotInUncertainOrPointeeSymbol(ST)){
                    // report a warning
                    PatchInfo *Patch=convertToPatch(ST,InsertOpaque);
                    Patch->After.push_back(E);
                    Patch->Variable=findDeclaration(ST);
                    Patches.push_back(Patch);
                    external_bug_report.addToReport(convertToReport(Patch));
                }
            }
        }
        // update
        CurrentResult->getSecond().LastStatus=Read?
            MRDetail::StatusType::READ:MRDetail::StatusType::WRITE;
		Pool->update(ST,InsertOpaque,E, Read);
    }
}

void MemoryRewriteAnalyzer::visitSymbolAddress(Symbol::SymbolType*ST,const clang::Expr*E){
    // NOTICE: when read some symbol address, we can not decide this symbol is to be read,
    // 		or written.Therefore, see this symbol to be read.
    // disable global scope.
    assert(E);
    if(AnalyzedLevel==0){
        return;
    }
    checkAndUpdateSymbol(MainFlow,ST,E,true);
    checkTopSymbol(ST,E,true);
    checkElementSymbol(ST,E,true);
}

void MemoryRewriteAnalyzer::visitSymbol(Symbol::SymbolType *ST,bool Read,const clang::Expr *E){
    if(AnalyzedLevel==0||!ST){
        return;
    }
    checkAndUpdateSymbol(MainFlow,ST,E,Read);
    checkTopSymbol(ST,E,Read);
    checkElementSymbol(ST,E,Read);
}

void MemoryRewriteAnalyzer::enterCallExpr(const clang::CallExpr *CE){
    const clang::Decl *D=CE->getCalleeDecl();
    if(D&&llvm::isa<clang::FunctionDecl>(D)){
        const clang::FunctionDecl *FD=llvm::cast<clang::FunctionDecl>(D);
        auto Flow=findFlowOfFunction(FD);
        if(Flow){
            checkAndUpdateFlow(MainFlow,Flow,true);
        }
    }
}


// check the element symbols,
// such as 
// struct s s1;
// s1.a=10;
// memset(&s1,0,sizeof(s1));
void MemoryRewriteAnalyzer::checkElementSymbol(Symbol::SymbolType *ST,const clang::Expr*E,bool Read){
    if(!ST){
        return;
    }
    if(Read){
        if(ST->is<Symbol::Record*>()){
            checkElementSymbolRead(ST,E);
        }
        return;
    }
    // The ElementExprs is used to gather the expressions when needed.
    // That means we can gather as many as we can to diagnose a warning.
    std::vector<const clang::Expr*> ElementExprs;
    if(ST->is<Symbol::Array*>()||ST->is<Symbol::Record*>()){
        if(checkElementSymbolWrite(ST,ElementExprs)){
            if(occursNotInUncertainOrPointeeSymbol(ST)){
                // report an warning.
                PatchInfo *Patch=new PatchInfo();
                for(auto&Val:ElementExprs){
                    Patch->Previous.push_back(Val);
                }
                Patch->After.push_back(E);
                Patch->Variable=findDeclaration(ST);
                external_bug_report.addToReport(convertToReport(Patch));
            }
        }
    }
}

void MemoryRewriteAnalyzer::checkElementSymbolRead(Symbol::SymbolType *ST,const clang::Expr*E){
    if(!ST){
        return;
    }
    if(ST->is<Symbol::Array*>()){
        auto A=ST->get<Symbol::Array*>();
        for(auto&Ele:A->ElementSymbols){
            checkElementSymbolRead(Ele.getSecond(),E);
        }
        checkElementSymbolRead(A->UncertainElementSymbol,E);
    }else if(ST->is<Symbol::Record*>()){
        auto R=ST->get<Symbol::Record*>();
        for(auto&Ele:R->Elements){
            checkElementSymbolRead(Ele.second,E);
        }
    }else if(ST->is<Symbol::Normal*>()||ST->is<Symbol::Pointer*>()){
        checkAndUpdateSymbol(MainFlow,ST,E,true);
    }
}
bool MemoryRewriteAnalyzer::checkElementSymbolWrite(Symbol::SymbolType *ST,std::vector<const clang::Expr*>&ElementExprs){
    if(!ST){
        return false;
    }
    bool Ret=false;
	const auto Content=MainFlow->Content;
    if(ST->is<Symbol::Array*>()){
        auto A=ST->get<Symbol::Array*>();
        for(auto&Ele:A->ElementSymbols){
            if(checkElementSymbolWrite(Ele.getSecond(),ElementExprs)){
                Ret=true;
            }
        }
        if(checkElementSymbolWrite(A->UncertainElementSymbol,ElementExprs)){
            Ret=true;
        }
    }else if(ST->is<Symbol::Record*>()){
        auto R=ST->get<Symbol::Record*>();
        for(auto&Ele:R->Elements){
            if(checkElementSymbolWrite(Ele.second,ElementExprs)){
                Ret=true;
            }
        }
    }else if(ST->is<Symbol::Normal*>()||ST->is<Symbol::Pointer*>()){
        auto Result=Content.find(ST);
        if(Result!=Content.end()){
            if(Result->getSecond().LastStatus==MRDetail::StatusType::WRITE
                ||Result->getSecond().LastStatus==MRDetail::StatusType::PARTIALLYWRITE){
                Ret=true;
				const auto& Exprs=Pool->getExprs(ST,computeEncryptedValue(MainFlow,false));
				for(const auto &Ele:Exprs){
					ElementExprs.push_back(Ele);
				}
            }
        }
    }
    return Ret;
}

int MemoryRewriteAnalyzer::getCountOfLoopStmt(const clang::ForStmt *FS){
    assert(DefaultLoopCount==1);
    return DefaultLoopCount;
}
void MemoryRewriteAnalyzer::checkTopSymbol(Symbol::SymbolType *ST,const clang::Expr*E,bool Read){
    if(!ST){
        return;
    }
	size_t InsertOpaque=computeEncryptedValue(MainFlow,false);
    Symbol::SymbolType* Top=Footprints::getParentSymbol(ST);
    // check the top symbol
    // such as 
    // struct s{int a;int b;}s1;
    // memset(&s1,0,sizeof(s1)
    // s1.a=10;s1.b=10;
    while(Top){
        if(Read){
            checkAndUpdateSymbol(MainFlow,Top,E,true);
            // update parent symbol.
            Top=Footprints::getParentSymbol(Top);
            continue;
        }
        std::vector<const clang::Expr*> ElementExprs;
        bool AllPoisoned=true;
		// denotes the elements number we find.
		size_t Count=0;
		auto Content=MainFlow->Content;
        // NOTICE: also check the rewrite!!
        if(Top->is<Symbol::Array*>()){
            auto A=Top->get<Symbol::Array*>();
            auto Result=Content.end();
            if(A->isConstantArray()){
                for(auto &Ele:A->ElementSymbols){
                    Result=Content.find(Ele.getSecond());
                    // must be write not partially write.
                    if(Result!=Content.end()
						&&Result->getSecond().LastStatus!=MRDetail::StatusType::WRITE){
                        AllPoisoned=false;
                        break;
                    }else if(Result==Content.end()){
                        continue;
                    }else{
						Count++;
						const auto& Tmp=Pool->getExprs(Ele.getSecond(),computeEncryptedValue(MainFlow,false));
                        ElementExprs.insert(ElementExprs.cend(),Tmp.begin(),Tmp.end());
                    }
                }
                Result=Content.find(Top);
                if(AllPoisoned&&Result!=Content.end()
                    &&(Result->getSecond().LastStatus==MRDetail::StatusType::WRITE
                    ||Result->getSecond().LastStatus==MRDetail::StatusType::PARTIALLYWRITE)){
					if(occursNotInUncertainOrPointeeSymbol(Top)){
						if(Count==A->ElementSize||(Count!=A->ElementSize&&!Overlap)){
							// report an warning.
							PatchInfo *Patch=convertToPatch(Top,InsertOpaque);
							for(auto&Val:ElementExprs){
								Patch->After.push_back(Val);
							}
							Patch->Variable=findDeclaration(Top);
                            Patches.push_back(Patch);
							external_bug_report.addToReport(convertToReport(Patch));
						}
                    }
					if(Count==A->ElementSize){
						Pool->update(Top,computeEncryptedValue(MainFlow,false),ElementExprs,false);
					}
                }else if(AllPoisoned&&Result==Content.end()&&Count==A->ElementSize){
					MRDetail::SymbolStatus Status;
					Status.FirstStatus=MRDetail::StatusType::WRITE;
					Status.LastStatus=MRDetail::StatusType::WRITE;
					MainFlow->Content.insert({ST,Status});
					Pool->update(Top,computeEncryptedValue(MainFlow,false),ElementExprs,false);
                }
            }
        }else if(Top->is<Symbol::Record*>()){
            auto R=Top->get<Symbol::Record*>();
            AllPoisoned=true;
            auto Result=Content.end();
            for(auto &Ele:R->Elements){
                Result=Content.find(Ele.second);
                if(Result!=Content.end()
					&&Result->getSecond().LastStatus!=MRDetail::StatusType::WRITE){
                    AllPoisoned=false;
                    break;
                }else if(Result==Content.end()){
                    continue;
                }else{
					Count++;
                    const auto &Tmp=Pool->getExprs(Ele.second,computeEncryptedValue(MainFlow,false));
                    ElementExprs.insert(ElementExprs.cend(),Tmp.begin(),Tmp.end());
                }
            }
            Result=Content.find(Top);
            if(AllPoisoned&&Result!=Content.end()
                &&(Result->getSecond().LastStatus==MRDetail::StatusType::WRITE
                ||Result->getSecond().LastStatus==MRDetail::StatusType::PARTIALLYWRITE)){
                    if(occursNotInUncertainOrPointeeSymbol(Top)){
						if(Count==R->Elements.size()||(Count!=R->Elements.size()&&!Overlap)){
							// report an warning.
							PatchInfo *Patch=convertToPatch(Top,InsertOpaque);
							for(auto&Val:ElementExprs){
								Patch->After.push_back(Val);
							}
							Patch->Variable=findDeclaration(Top);
							external_bug_report.addToReport(convertToReport(Patch));
						}
                    }
					if(Count==R->Elements.size()){
						Pool->update(Top,computeEncryptedValue(MainFlow,false),ElementExprs,false);
					}
            }else if(AllPoisoned&&Result==Content.end()&&Count==R->Elements.size()){
                MRDetail::SymbolStatus Status;
				Status.FirstStatus=MRDetail::StatusType::WRITE;
				Status.LastStatus=MRDetail::StatusType::WRITE;
				MainFlow->Content.insert({ST,Status});
				Pool->update(Top,computeEncryptedValue(MainFlow,false),ElementExprs,false);
            }
        }
        // update parent symbol.
        Top=Footprints::getParentSymbol(Top);
    }
}

bool MemoryRewriteAnalyzer::occursNotInUncertainOrPointeeSymbol(const Symbol::SymbolType*ST){
    Symbol::SymbolType *Current=const_cast<Symbol::SymbolType*>(ST);
    Symbol::SymbolType *Top=nullptr;
    do{
        Top=Footprints::getParentSymbol(Current);
        if(!Top||Top->isNull()){
            return true;
        }
        if(Top->is<Symbol::Array*>()){
            if(Top->get<Symbol::Array*>()->UncertainElementSymbol==Current){
                return false;
            }
        }else if(Top->is<Symbol::Pointer*>()){
            Symbol::Pointer *P=Top->get<Symbol::Pointer*>();
            if(P->OffsetStack.size()<2){
                Current=Top;
                continue;
            }
            auto Second=P->OffsetStack[P->OffsetStack.size()-2];
            if(P->OffsetStack.back()==llvm::None||Second==llvm::None){
                return false;
            }else if(P->OffsetStack.back().getValue()!=Second.getValue()){
                return false;
            }
        }
        Current=Top;
    }while(Top);
    return true;
}

bool MemoryRewriteAnalyzer::checkAliasRedundancy(const Symbol::SymbolType *ST){
	// TODO:
	return false;
}

MemoryRewriteAnalyzer::PatchInfo* MemoryRewriteAnalyzer::convertToPatch(Symbol::SymbolType*ST,size_t After,size_t Before){
    MemoryRewriteAnalyzer::PatchInfo* Patch=new MemoryRewriteAnalyzer::PatchInfo();
    for(const auto& Ele:Pool->Pool){
        if(Ele.getFirst()==ST){
            for(const auto &Expr:Ele.getSecond()){
                if(Expr.Id==Before&&!Expr.Read){
                    Patch->Previous.push_back(Expr.Op);
                }
                if(Expr.Id==After&&!Expr.Read){
                    Patch->After.push_back(Expr.Op);
                }
            }
        }
    }
    return Patch;
}

MemoryRewriteAnalyzer::PatchInfo* MemoryRewriteAnalyzer::convertToPatch(Symbol::SymbolType*ST,size_t Before){
    MemoryRewriteAnalyzer::PatchInfo* Patch=new MemoryRewriteAnalyzer::PatchInfo();
    for(const auto& Ele:Pool->Pool){
        if(Ele.getFirst()==ST){
            for(const auto &Expr:Ele.getSecond()){
                if(Expr.Id==Before&&!Expr.Read){
                    Patch->Previous.push_back(Expr.Op);
                }
            }
        }
    }
    return Patch;
}

ReportSpace::Defect *MemoryRewriteAnalyzer::convertToReport(MemoryRewriteAnalyzer::PatchInfo *Patch){
    // get the file of the patch location.
    const clang::SourceManager &SM=Context->getSourceManager();
    clang::SourceLocation Loc=Patch->Variable->getBeginLoc();
    unsigned int line=SM.getExpansionLineNumber(Loc);
    unsigned int column=SM.getExpansionColumnNumber(Loc);
    llvm::StringRef VariableName=Patch->Variable->getName();
    std::string FilePathName=Loc.printToString(SM);
    ReportSpace::Defect *D=new ReportSpace::Defect(ReportSpace::MemoryRewrite
            ,ReportSpace::Warning,FilePathName,line,column,VariableName.str());
    std::ostringstream extra;
    extra<<"memory rewrite on "<<VariableName.data();
    extra<<".Previous write operation(s) on line ";
    for(auto&Val:Patch->Previous){
        extra<<SM.getExpansionLineNumber(Val->getBeginLoc())<<";";
    }
    extra<<"Current write operation(s) on line ";
    for(auto&Val:Patch->After){
        extra<<SM.getExpansionLineNumber(Val->getBeginLoc())<<";";
    }
	extra << "In function:" << CurrentFunction->getName().data();
	extra << "(line:" << SM.getExpansionLineNumber(CurrentFunction->getBeginLoc()) << ")";
    // add extra info.
    D->addDesc(extra.str());
    return D;
}


// TODO: complete the method
void MemoryRewriteAnalyzer::reportToConsole(MemoryRewriteAnalyzer::PatchInfo *Patch) {
}


void MemoryRewriteChecker::readConfig(MemoryRewriteAnalyzer *Analyzer){
    std::unordered_map<std::string, std::string> Config =
                configure->getOptionBlock("MemoryRewriteChecker");
    if(Config::IsBlockConfigTrue(Config,"IgnoreCStandardLibrary")){
        Analyzer->setIgnoreCStandardLibrary(true);
    }else{
        Analyzer->setIgnoreCStandardLibrary(false);
    }
    if(Config::IsBlockConfigTrue(Config,"DisableSimpleVariable")){
        Analyzer->DisableSimpleVariable=true;
    }else{
        Analyzer->DisableSimpleVariable=false;
    }
	// If configuration is not set, we still want it set it true.
    // but IsBlockConfigTrue will also return false.
    const auto FindResult=Config.find("Overlap");
    if(FindResult!=Config.end()){
        if(FindResult->second=="true"){
            Analyzer->Overlap=true;
        }else if(FindResult->second=="false"){
            Analyzer->Overlap=false;
        }
    }else {
        Analyzer->Overlap = true;
    }
    IgnorePaths=configure->parseIgnPaths("MemoryRewriteChecker");
    for(auto& Path:IgnorePaths.getIgnoreLibPaths()){
        Analyzer->addIgnoreDir(Path);
    }
}

void MemoryRewriteChecker::check(){
    size_t NumOfAnalyzedFiles=0;
    size_t NumOfTotalFiles=resource->getASTFiles().size();
    for(const auto &File:resource->getASTFiles()){
        NumOfAnalyzedFiles++;
        auto *SingleChecker= new MemoryRewriteAnalyzer( &(manager->getASTUnit(File)->getASTContext()));
        readConfig(SingleChecker);
        addSingleChecker(SingleChecker);
        SingleChecker->analyze();
        process_bar((float)NumOfAnalyzedFiles/NumOfTotalFiles);
    }
}